package Simulator;

import Shared.MapPosition;
import Shared.MsgType;

/**
 * The AmbulanceSimulator module, see Architecture report for specifications.
 */

public class AmbulanceSimulator implements Runnable {

	private EnvironmentDatabase db;

	private static final int refresh_time = 1000;

	private boolean halted;

	private static AmbulanceSimulator singleton = new AmbulanceSimulator();

	/**
	 * @return the unique RadioSoftware instance.
	 */
	public static AmbulanceSimulator getInstance() {
		return singleton;
	}

	private AmbulanceSimulator() {
		this.db = EnvironmentDatabase.getInstance();
		this.halted = false;
	}

	/**
	 * Simulates the ambulance's drivers and moves all the ambulance one step
	 * closer to their assigned destination if they have one.
	 */
	public void moveAllAmbulances() {

		for (RealAmbulance amb : db.getAllAmbulances()) {
			/* move to next node */

			MapPosition dest = amb.getMdt().getAssignedDestination();
			if (dest != null) {
				MapPosition nextStep = amb.getMdt().getNextMapPosition(dest);
				if (nextStep != null) // src != dest,
					amb.setPosition(nextStep);

			} else {
				// TODO Detection des ambulances statiques.
				// TODO Gestion d'ambulance occupées.
				// amb.idle_turns_count ++;
				//
				// if ( amb.idle_turn_count > 4)
				// amb.setDestination(hopital ou random) // !!! pas utiliser
				// assign !!!
				//
				if (amb.isBusy()) {
					amb.setFree();
					amb.getMdt().getRadio().send(MsgType.FREE, amb.getID());

				}
			}
		}
	}

	/**
	 * Loop over moveAllAmbulances() at certain rate if the simulation is not
	 * halted.
	 */
	public void run() {
		try {
			while (true) {
				this.moveAllAmbulances();
				synchronized (this) {
					while (this.isHalted()) {
						wait();
					}
				}
				Thread.sleep(refresh_time);
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 
	 * @return true if the simulation is not halted
	 */
	public boolean isHalted() {
		return this.halted;
	}

	/**
	 * Set the simulation as halted or not.
	 * 
	 * @param halt
	 *            true to halt the simulation, false to unhalt it.
	 */
	public void setHalted(boolean halt) {
		this.halted = halt;
		if (!halt)
			this.notify();
	}

}
